/**
 * Displays a Discard? dialog and redirects back to index.
 */
function cancelEntry() {
	location.href = 'index.xhtml';
}

function isMobile() {
	return $('#isMobile').css('margin-top') == '1px';
}

/**
 * Sets the focus to the form's first input element.
 */
function focusForm() {
	if ($('form').length == 0) return;
	var autoFocus = $('form').find('.focus');
	if (autoFocus.length > 0) {
		autoFocus.first().focus();
		return;
	}
	var inputElements = $('form.primary').find("input[type='text'], input[type='password'], textarea, select");
	if (inputElements.length == 0) {
		inputElements = $('form').find("input[type='text'], input[type='password'], textarea, select");
	}
	if (inputElements.length == 0) return;
	inputElements.first().focus();
}

function activateSessionTimeoutTimer() {
	if (!isLoggedIn) return;
	var sessionTimeoutTimer = $('html').data('sessionTimeoutTimer');
	if (sessionTimeoutTimer) {
		window.clearTimeout(sessionTimeoutTimer);
	}
	sessionTimeoutTimer = window.setTimeout(function() {
		window.location.href = './login.xhtml?sessionTimeout=1';
	}, 1000*60*5);
	$('html').data('sessionTimeoutTimer', sessionTimeoutTimer);
}

function deleteKeeBook() {
	if (confirm('Are you sure you want to delete the current kee book? All entries stored in the book will be discarded. This can\'t be undone.')) {
		location.href = './renamekeebook.xhtml?delete=1';
	}
}

function unsubscribeKeeBook() {
	if (confirm('Are you sure you want to unsubscribe from the current kee book?')) {
		location.href = './renamekeebook.xhtml?delete=1';
	}
}

/**
 * Switched the password fields between type=password and type=text.
 * Not compatible with IE < 9.
 */
function switchPasswordVisibility(field1, field2) {
	try {
		var currentType = $('[id$=":'+field1+'"]').attr('type');
		var password1name = $('[id$=":'+field1+'"]').attr('id');
		document.getElementById(password1name).type = (currentType == 'password' ? 'text' : 'password');
		if (field2) {
			currentType = $('[id$=":'+field2+'"]').attr('type');
			password1name = $('[id$=":'+field2+'"]').attr('id');
			document.getElementById(password1name).type = (currentType == 'password' ? 'text' : 'password');
		}
	} catch (error) {
		// Do nothing...
	}
}

/**
 * Checks via trial-and-error if the visibility of passwords can be toggled
 * (as not all browsers support this, i.e. IE < 9).
 * If not, the toggle-button is made invisible.
 */
function checkPasswordSwitchCompatibility() {
	if ($('.passwordVisibilitySwitcher').length == 0) return;
	try {
		var firstId = $('[id$=":password"]').attr('id');
		document.getElementById(firstId).type = 'text';
		document.getElementById(firstId).type = 'password';
	} catch (error) {
		$('.passwordVisibilitySwitcher').css('display', 'none');
	}
}

function updateCreateKeeBookForm() {
	var fieldId = $('[id$=":masterPassword"]').attr('id');
	setMasterPassword(document.getElementById(fieldId).value);
	var salt = $('[id$=":salt"]').val();
	if (document.getElementById(fieldId).value != '') {
		document.getElementById(fieldId).value = hash(document.getElementById(fieldId).value, salt);
	}
}

function updateSelectKeeBookForm() {
	var fieldId = $('[id$=":masterPassword"]').attr('id');
	setMasterPassword(document.getElementById(fieldId).value);
	var keeBookId = $('[id$=":keeBookId"]').val();
	var salt = keeBookSalts[keeBookId];
	document.getElementById(fieldId).value = hash(document.getElementById(fieldId).value, salt);
	sessionStorage.setItem('keeBook', keeBookId);
	sessionStorage.setItem('salt', salt);
}

function onAddEntryFormInit() {
	if ($('#addEntryForm').length == 0) return;
	var field1Id = $('[id$=":password"]').attr('id');
	if (document.getElementById(field1Id).value != '') {
		document.getElementById(field1Id).value = decrypt(document.getElementById(field1Id).value);
	}
	if ($('[id$=":username"]').val() != '') {
		$('[id$=":username"]').val(decrypt($('[id$=":username"]').val()));
	}
	if ($('[id$=":url"]').val() != '') {
		$('[id$=":url"]').val(decrypt($('[id$=":url"]').val()));
	}
	if ($('[id$=":notes"]').val() != '') {
		$('[id$=":notes"]').val(decrypt($('[id$=":notes"]').val()));
	}
	if (document.getElementById(field1Id).value == '') {
		var generatedPassword = generatePassword();
		document.getElementById(field1Id).value = generatedPassword;
	}
	$('[id=\'passwordGenerator:generatedPassword\']').val(generatePassword());
	$('[id$=":password"]').passwordStrength({
		'container': $('#addEntryForm\\:passwordStrength')
	});
	$('[id$=":generatedPassword"]').passwordStrength({
		'container': $('#passwordGenerator\\:passwordStrength')
	});
	$('#addEntryForm\\:group').bind('change', function() {
		if ($(this).val() == 'c') {
			$('#groupNameContainer').slideDown();
		} else {
			$('#groupNameContainer').slideUp();
		}
	});
	$('#groupNameContainer').css('height', $('#groupNameContainer').height()).hide();
	if ($('#addEntryForm\\:group').val() == 'c') {
		$('#groupNameContainer').show();
	}
	$('#addEntryForm').validate({
		errorElement: 'span',
		highlight: function(element, errorClass, validClass) {
			
		},
		rules: {
			'addEntryForm:title': {
				required: true
			},
			'addEntryForm:password1': {
				required: true
			}
		},
		messages: {
			'addEntryForm:title': {
				required: 'Please enter a title'
			},
			'addEntryForm:password1': {
				required: 'Please enter a password'
			}
		},
		errorPlacement: function(error, element) {
			error.appendTo(element.parent());
		},
		submitHandler: function(form) {
			var field1Id = $('[id$=":password"]').attr('id');
			document.getElementById(field1Id).value = encrypt(document.getElementById(field1Id).value);
			if ($('[id$=":url"]').val() != '') {
				$('[id$=":url"]').val(encrypt($('[id$=":url"]').val()));
			}
			if ($('[id$=":notes"]').val() != '') {
				$('[id$=":notes"]').val(encrypt($('[id$=":notes"]').val()));
			}
			if ($('[id$=":username"]').val() != '') {
				$('[id$=":username"]').val(encrypt($('[id$=":username"]').val()));
			}
			form.submit();
		}
	});
	
	// Set up username autocompletion:
	// Load usernames in background, decrypt, store in Session Storage, and setup autocompletion.
	// Get usernames directly from Session Storage if loaded before.
	if (sessionStorage.getItem('usernameSuggest') != null) {
		var usernames = JSON.parse(sessionStorage.getItem('usernameSuggest'));
		$('[id$=":username"]').autocomplete({'data': usernames, 'minChars': 1, 'delay': 100});
	} else {
		$.ajax({
			'contentType': 'application/json',
			'type': 'GET',
			'url': './services/usersuggest',
			'success': function(data) {
				var usernames = new Array();
				for (var i=0; i<data.length; i++) {
					var username = decrypt(data[i]);
					if ($.inArray(username, usernames) == -1) {
						usernames.push(username);
					}
				}
				usernames.sort();
				$('[id$=":username"]').autocomplete({'data': usernames, 'minChars': 1, 'delay': 100});
				sessionStorage.setItem('usernameSuggest', JSON.stringify(usernames));
			}
		});
	}
}

function onChangePassphraseFormInit() {
	if ($('#changePassphraseForm').length == 0) return;
	$.validator.addMethod("checkMasterPassword", function(value) {
		return value == getMasterPassword();
	}, 'Incorrect passphrase');
	$('#changePassphraseForm').validate({
		errorElement: 'span',
		highlight: function(e) {
			$(e).removeClass('valid');
			onFormErrorsInit();
		},
		unhighlight: function(e) {
			$(e).addClass('valid');
			onFormErrorsInit();
		},
		rules: {
			'changePassphraseForm:currentPassword': 'checkMasterPassword',
			'changePassphraseForm:password': {
				required: true
			},
			'changePassphraseForm:passwordChecked': {
				required: true
			}
		},
		messages: {
			'changePassphraseForm:password': {
				required: 'Please enter a passphrase'
			},
			'changePassphraseForm:passwordChecked': {
				required: 'Please check your passphrase'
			}
		},
		errorPlacement: function(error, element) {
			error.appendTo(element.parent());
		},
		submitHandler: function(form) {
			updateMasterPassphrase(document.getElementById($('[id$=":password"]').attr('id')).value);
		}
	});
}

function updateMasterPassphrase(newPassphrase, cb) {
	var username = 'null';
	var password = '';
	
	// 1st: Get all password items from current key book
	var data = {
		'username': username,
		'auth': 'session',
		'password': password,
		'keeBook': getKeeBookId(),
		'keeBookChecksum': hash(getMasterPassword(), getSalt())
	};
	$.ajax({
		'data': data,
		'contentType': 'application/json',
		'type': 'GET',
		'dataType': 'json',
		'url': './services/'+username+'/getitem',
		'success': function(data) {
			// 2nd: Encrypt all encrypted details from each item with the new passphrase
			var updatedItems = new Array();
			for (var i=0; i<data.count; i++) {
				var oldItem = data.result[i];
				var newItem = {
					'id': oldItem['id'],
					'username': encrypt(decrypt(oldItem['username']), newPassphrase),
					'password': encrypt(decrypt(oldItem['password']), newPassphrase),
					'url': encrypt(decrypt(oldItem['url']), newPassphrase),
					'notes': encrypt(decrypt(oldItem['notes']), newPassphrase)
				};
				updatedItems.push(newItem);
			}
			var postObject = {
				'username': username,
				'auth': 'session',
				'password': password,
				'keeBook': getKeeBookId(),
				'keeBookChecksum': hash(getMasterPassword(), getSalt()),
				'items': updatedItems
			};
			$.ajax({
				'data': JSON.stringify(postObject),
				'contentType': 'application/json',
				'type': 'POST',
				'dataType': 'json',
				'url': './services/'+username+'/setitem',
				'success': function(data) {
					// 3rd: Update the current key book's master passphrase checksum
					var newChecksum = hash(newPassphrase, getSalt());
					var postObject = {
						'username': username,
						'password': password,
						'auth': 'session',
						'keeBook': getKeeBookId(),
						'keeBookChecksum': hash(getMasterPassword(), getSalt()),
						'data': {
							'keeBookChecksum': newChecksum
						}
					};
					$.ajax({
						'data': JSON.stringify(postObject),
						'contentType': 'application/json',
						'type': 'POST',
						'dataType': 'json',
						'url': './services/'+username+'/updatekeebook',
						'success': function(data) {
							setMasterPassword(newPassphrase);
							location.href = './changepassphrase.xhtml?msg=12';
						}
					});
				}
			});
		}
	});
}

function showAppMessage(s) {
	$('#appMessage').text(s).hide().fadeIn();
}

function selectText(element) {
	if (element != null) {
		var obj = document.getElementById(element);
		var range = rangy.createRange();
		range.selectNodeContents(obj);
		var sel = rangy.getSelection();
		sel.setSingleRange(range);
	} else {
		var sel = rangy.getSelection();
		sel.removeAllRanges();
	}
}

function deselectAllListFields() {
	var copyTimer = $('.passwordList').data('copyTimer');
	if (copyTimer) {
		window.clearInterval(copyTimer);
	}
	if ($('.passwordList').find('.usernameLink,.passwordLink').hasClass('selected')) {
		$('.passwordList').find('.passwordLink').text('••••••••');
		$('.passwordList').find('.usernameLink,.passwordLink').removeClass('selected');
		$('#copyHint').hide();
		selectText(null);
	}
}

function compareString(a, b) {
	if (a == b) return 0;
	var ab = [a, b].sort();
	if (ab[0] == a) return -1;
	return 1;
}

function getItemGroupTitle(tr) {
	var header = tr.prevAll('tr.groupHeader:first');
	if (header.length == 1) {
		return header.find('td.titleColumn').text();
	}
	return '';
}

function getTargetNextSibling(tr, isFavor) {
	var result = null;
	var currentGroup = '';
	var title = tr.find('a.titleLink').text();
	var group = getItemGroupTitle(tr);
	$('.passwordList').find('tr').each(function() {
		if ($(this).hasClass('groupHeader')) {
			if (group == currentGroup && result == null) result = $(this);
			currentGroup = $(this).find('td.titleColumn').text();
			return;
		}
		if (group != currentGroup) return;
		var currentTitle = $(this).find('a.titleLink').text();
		var currentFavor = $(this).find('.favorLink').hasClass('active');
		if (isFavor && !currentFavor && result == null) {
			result = $(this);
		} else if (isFavor && currentFavor) {
			var compareResult = compareString(title, currentTitle);
			if (compareResult == -1) result = $(this);
		} else if (!isFavor && !currentFavor && result == null) {
			var compareResult = compareString(title, currentTitle);
			if (compareResult == -1) result = $(this);
		}
	});
	return result;
}

function activateUserPassCopyTimeout() {
	var copyTimer = $('.passwordList').data('copyTimer');
	if (copyTimer) {
		window.clearInterval(copyTimer);
	}
	$('#copyHint .timer').text('5');
	copyTimer = window.setInterval(function() {
		var sec = parseInt($('#copyHint .timer').text())-1;
		$('#copyHint .timer').text(sec);
		if (sec <= 0) {
			deselectAllListFields();
			window.clearInterval($('.passwordList').data('copyTimer'));
		}
	}, 1000);
	$('.passwordList').data('copyTimer', copyTimer);
}

function onEntryListInit() {
	$(window).resize(function() {
		var field = $('#' + $('#copyHint').data('fieldId'));
		var pos = field.position();
		$('#copyHint').css({
			'display': 'block',
			'left': pos.left + 'px',
			'top': (pos.top - $('#copyHint').outerHeight()) + 'px'
		});
	});
	
	if ($('.passwordList').length == 0) return;
	$('.passwordList').find('td.titleColumn').each(function() {
		$(this).bind('click', function() {
			location.href = $(this).children('a').last().attr('href');
		});
	});
	$('.passwordList').find('.urlLink').each(function() {
		$(this).attr('href', decrypt($(this).attr('href')));
	});
	$('.passwordList').find('.favorLink').each(function() {
		$(this).bind('click', function() {
			if (!$(this).hasClass('canChange')) {
				return false;
			}
			var req = JSON.stringify({id: $(this).prev('.itemId').text(), favored: !$(this).hasClass('active')});
			if ($(this).hasClass('active')) {
				$(this).removeClass('active');
			} else {
				$(this).addClass('active');
			}
			$.ajax({
				'data': req,
				'contentType': 'application/json',
				'type': 'POST',
				'dataType': 'json',
				'url': './services/setfavored'
			});
			var tr = $(this).parents('tr').first();
			var targetNextSibling = getTargetNextSibling(tr, $(this).hasClass('active'));
			if (targetNextSibling != null && tr.next('tr').get(0) === targetNextSibling.get(0)) return false;
			if (targetNextSibling == null && tr.next('tr').length == 0) return false;
			tr.fadeOut(200, function() {
				if (targetNextSibling == null) {
					$('.passwordList').children('tbody').append(tr);
				} else {
					tr.insertBefore(targetNextSibling);
				}
				tr.fadeIn(400);
			});
			return false;
		});
	});
	$('.passwordList').find('.itemId.highlight').each(function() {
		$(this).parents('tr').addClass('highlight');
	});
	$('.passwordList').find('.usernameLink').each(function() {
		$(this).text(decrypt($(this).text()));
		$(this).attr('id', 'usernameLink-' + $(this).parents('tr').find('.itemId').text());
		$(this).bind('click', function(e) {
			deselectAllListFields();
			selectText($(this).attr('id'));
			$(this).addClass('selected');
			$('#copyHint').data('fieldId', $(this).attr('id'));
			activateUserPassCopyTimeout();
			activateSessionTimeoutTimer();
			$(window).trigger('resize');
			e.stopPropagation();
		});
	});
	$('.passwordList').find('.passwordLink').each(function() {
		$(this).text('••••••••');
		$(this).attr('id', 'passwordLink-' + $(this).parents('tr').find('.itemId').text());
		$(this).bind('click', function(e) {
			$('html').trigger('click');
			$(this).text(decrypt($(this).prev('.passwordContainer').text()));
			selectText($(this).attr('id'));
			$(this).addClass('selected');
			$('#copyHint').data('fieldId', $(this).attr('id'));
			activateUserPassCopyTimeout();
			activateSessionTimeoutTimer();
			$(window).trigger('resize');
			e.stopPropagation();
		});
	});
	
	renderItemGroups();
	
	$('html').bind('click', function() {
		deselectAllListFields();
	});
	
	$(document).bind('keyup', function(e) {
		if (e.keyCode == 27) { // Escape key
			deselectAllListFields();
		}
	});
	
	$('#decryptingHint').css('display', 'none');
	$('.passwordList').css('display', 'table');
}

function renderItemGroups() {
	if (!isRenderItemGroups) return;
	var lastGroupTitle = null;
	$('.passwordList').find('div.groupTitle').each(function() {
		var groupTitle = $(this).text();
		if (lastGroupTitle != groupTitle && groupTitle != '') {
			var tr = $(document.createElement('tr'));
			tr.addClass('groupHeader');
			for (var i = 1; i<=5; i++) {
				var td = $(document.createElement('td'));
				td.attr('class', $(this).parents('tr').children('td:nth-child('+i+')').attr('class'));
				if (i == 1) {
					td.text(groupTitle);
				}
				tr.append(td);
			}
			tr.insertBefore($(this).parents('tr'));
		}
		lastGroupTitle = groupTitle;
	});
}

function getMasterPassword() {
	var s = sessionStorage.getItem('masterPassword');
	if (!s || s == '') {
		$('#tabHint').show();
		$('#tabHint').nextAll().hide();
	}
	return s;
}

function setMasterPassword(s) {
	sessionStorage.setItem('masterPassword', s);
}

function encrypt(s, passphrase) {
	var masterPassword = passphrase ? passphrase : getMasterPassword();
	return Crypto.AES.encrypt(s, masterPassword);
}

function decrypt(s) {
	var masterPassword = getMasterPassword();
	try {
		return Crypto.AES.decrypt(s, masterPassword);
	} catch (error) {
		return '';
	}
}

function hash(s, salt) {
	return Crypto.SHA256(Crypto.SHA256(s) + salt);
}

function getKeeBookId() {
	return sessionStorage.getItem('keeBook');
}

function getSalt() {
	return sessionStorage.getItem('salt');
}

function checkBrowserCompatibility() {
	$('#jsNotSupportedError').css('display', 'none');
	if (typeof(sessionStorage) == 'undefined' || sessionStorage == null || sessionStorage == undefined) {
		$('#ssNotSupportedError').css('display', 'block');
		$('#loginForm').css('display', 'block');
		return;
	}
	$('#loginContainer').css('display', 'block');
}

function logout() {
	sessionStorage.removeItem('masterPassword');
	sessionStorage.removeItem('keeBook');
	sessionStorage.removeItem('salt');
	sessionStorage.removeItem('usernameSuggest');
	sessionStorage.clear();
}

function showTopPopup(e) {
	$('.topPopup').show('fast');
	activateSessionTimeoutTimer();
	e.stopPropagation();
}

function hideTopPopup() {
	$('.topPopup').hide();
}

function getGeneratorSettings() {
	var settings = new Object();
	settings['length'] = $('#passwordGenerator\\:length').val();
	settings['upperCase'] = $('#passwordGenerator\\:upperCase').is(':checked');
	settings['lowerCase'] = $('#passwordGenerator\\:lowerCase').is(':checked');
	settings['digits'] = $('#passwordGenerator\\:digits').is(':checked');
	settings['minus'] = $('#passwordGenerator\\:minus').is(':checked');
	settings['underline'] = $('#passwordGenerator\\:underline').is(':checked');
	settings['space'] = $('#passwordGenerator\\:space').is(':checked');
	settings['special'] = $('#passwordGenerator\\:special').is(':checked');
	settings['brackets'] = $('#passwordGenerator\\:brackets').is(':checked');
	settings['highAnsi'] = $('#passwordGenerator\\:highAnsi').is(':checked');
	return settings;
}

function acceptGeneratedPassword() {
	var generatedPassword = $('[id$=":generatedPassword"]').val();
	$('[id$=":password"]').val(generatedPassword);
	$('[id$=":password"]').trigger('change');
	$('#acceptGeneratedButton').attr("disabled", "disabled");
	$.ajax({
		'data': JSON.stringify(getGeneratorSettings()),
		'contentType': 'application/json',
		'type': 'POST',
		'dataType': 'json',
		'url': './services/savegeneratorsettings',
		'success': function(data) {
			if (!data.success) {
				alert('Error from server: Could not save generator preferences.');
			}
			$('#acceptGeneratedButton').removeAttr("disabled");
			scrollMultiPartContent('partAddEntry');
		}
	});
}

function generatePassword() {
	var settings = getGeneratorSettings();
	var length = settings['length'];
	var chars = '';
	if (settings['upperCase']) {
		chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	}
	if (settings['lowerCase']) {
		chars += 'abcdefghijklmnopqrstuvwxyz';
	}
	if (settings['digits']) {
		chars += '0123456789';
	}
	if (settings['minus']) {
		chars += '-';
	}
	if (settings['underline']) {
		chars += '_';
	}
	if (settings['space']) {
		chars += ' ';
	}
	if (settings['special']) {
		chars += '!"§$%&/=?+*~#:;,|';
	}
	if (settings['brackets']) {
		chars += '{}[]()<>';
	}
	if (settings['highAnsi']) {
		for (var h=128; h<=255; h++) {
			chars += String.fromCharCode(h);
		}
	}
	if (chars == '') {
		return '';
	}
	var result = '';
	for (var i=1; i<=length; i++) {
		result += chars.charAt(Math.floor(Math.random()*chars.length));
	}
	return result;
}

function positionTopBar() {
	$('.top').css('top', $(document).scrollTop()+'px');
	$('.topSearchBar').css('top', (25+$(document).scrollTop())+'px');
}

function onImportFormInit() {
	if ($('#importForm').length == 0) return;
	$('#importForm').bind('submit', function() {
		$('[id="importForm:encryptionPassword"]').val(getMasterPassword());
	});
}

function onExportFormInit() {
	if ($('#exportForm').length == 0) return;
	$('#exportForm').bind('submit', function() {
		$('[id="exportForm:encryptionPassword"]').val(getMasterPassword());
	});
}

function setupPopupMenuClick() {
	$('#topPopupLink').bind('click', showTopPopup);
	$('html').bind('click', hideTopPopup);
}

function onSearchFormInit() {
	var field = $('#searchHeader\\:s');
	if (field.length == 0) return;
	var options = {
			'url': './services/searchsuggest',
			'minChars': 1,
			'delay': 100
	};
	field.autocomplete(options);
	field.bind('keyup', function() {
		if ($.trim($(this).val()) == '') {
			$('#clearSearch').hide();
		} else {
			$('#clearSearch').show();
		}
	});
	field.trigger('keyup');
	$('#clearSearch').bind('click', function() {
		field.val('');
		$('#searchHeader').submit();
	});
}

function onSignupFormInit() {
	if ($('#signupForm').length == 0) return;
	$('#signupForm\\:password').passwordStrength({
		'container': $('#signupForm\\:passwordStrength')
	});
}

function onResetPasswordFormInit() {
	if ($('#resetPasswordForm').length == 0) return;
	$('#resetPasswordForm\\:password').passwordStrength({
		'container': $('#resetPasswordForm\\:passwordStrength')
	});
}

function hideMessage() {
	$('div.message').slideUp(200);
}

function onCheckboxInit() {
	$("input[type='checkbox']").each(function() {
		$(this).addClass('invisible');
		var oldCheckbox = $(this);
		var newCheckbox = $(document.createElement('div'));
		newCheckbox.addClass('checkbox');
		newCheckbox.attr('style', oldCheckbox.attr('style'));
		newCheckbox.insertAfter($(this));
		newCheckbox.bind('click', function() {
			oldCheckbox.attr('checked', !oldCheckbox.is(':checked'));
			oldCheckbox.trigger('change');
		});
		oldCheckbox.bind('change', function() {
			if ($(this).is(':checked')) {
				newCheckbox.addClass('checked');
			} else {
				newCheckbox.removeClass('checked');
			}
		});
		if (oldCheckbox.is(':checked')) {
			oldCheckbox.trigger('change');
		}
		oldCheckbox.parent().append(oldCheckbox);
	});
}

function onSelectInit() {
	$("select").each(function() {
		$(this).css('display', 'none');
		var oldSelect = $(this);
		var newSelect = $(document.createElement('div'));
		newSelect.attr('class', oldSelect.attr('class'));
		newSelect.addClass('select');
		if (oldSelect.is(':disabled')) {
			newSelect.addClass('disabled');
		}
		newSelect.insertAfter($(this));
		
		var label = $(document.createElement('div'));
		label.addClass('label');
		newSelect.append(label);
		
		var ul = $(document.createElement('ul'));
		newSelect.append(ul);
		
		if ($(this).children('option').length > 1) {
			var dropdownButton = $(document.createElement('div'));
			dropdownButton.addClass('dropdownButton');
			newSelect.append(dropdownButton);
			
			newSelect.bind('click', function(e) {
				if (oldSelect.is(':disabled')) {
					return;
				}
				newSelect.addClass('focus');
				ul.show();
				activateSessionTimeoutTimer();
				e.stopPropagation();
			});
		}
		
		var createField = $("input[id='"+$(this).attr('id')+'Name'+"']");
		if (createField.length == 1) {
			createField.detach();
			newSelect.append(createField);
			createField.hide();
		}
		
		$(this).children('option').each(function() {
			var option = $(this);
			var title = $(this).text();
			var isCreateOption = ($(this).val() == 'c');
			
			var li = $(document.createElement('li'));
			li.text(title);
			if (isCreateOption) {
				li.addClass('createOption');
			}
			ul.append(li);
			
			if ($(this).is(':selected')) {
				label.text(title);
			}
			
			li.bind('click', function(e) {
				if (isCreateOption) {
					createField.show();
					createField.focus();
				} else {
					label.text(title);
					createField.hide();
				}
				option.attr('selected', true);
				newSelect.removeClass('focus');
				ul.fadeOut(100);
				activateSessionTimeoutTimer();
				e.stopPropagation();
			});
		});
		
		$('html').bind('click', function() {
			newSelect.removeClass('focus');
			ul.fadeOut(100);
		});
	});
}

function onDropdownMenuInit() {
	if ($('.dropdown-menu').length == 0) return;
	$('.dropdown-menu').bind('click', function(e) {
		if ($(this).children('ul').is(":visible")) {
			$(this).children('ul').fadeOut(100);
			$(this).removeClass('active');
			$('#layer').css('display', 'none');
		} else {
			$(this).children('ul').slideDown(150);
			$(this).addClass('active');
			$('#layer').css('display', 'block');
		}
		activateSessionTimeoutTimer();
		e.stopPropagation();
	});
	$('html').bind('click', function() {
		$('.dropdown-menu').children('ul').fadeOut(100);
		$('.dropdown-menu').removeClass('active');
		$('#layer').css('display', 'none');
	});
}

function onMultiPartContentInit() {
	if ($('#multiPartContainer').length == 0) return;
	var activePart = $('#multiPartContainer').children('.multiPart').first();
	$('#multiPartContainer').children('.multiPart').not('[id="'+activePart.attr('id')+'"]').height(1).css('visibility', 'hidden');
	$('#multiPartContainer').data('activePart', activePart.attr('id'));
}

function scrollMultiPartContent(focusId) {
	$('#'+focusId).css('visibility', 'visible').height('auto');
	var position = $('#'+focusId).position();
	$('#multiPartContainer').animate({'scrollLeft': position.left}, 250, 'swing', function() {
		$('#multiPartContainer').children('.multiPart').not('[id="'+focusId+'"]').height(1).css('visibility', 'hidden');
	});
	$('#multiPartContainer').data('activePart', $('#'+focusId).attr('id'));
}

function onPasswordFieldInit() {
	$("input[type='password'].generatable").each(function() {
		var button = $(document.createElement('div'));
		button.addClass('fieldButton');
		button.css('background-image', "url('images/edit.png')");
		$(this).after(button);
		$(this).css('width', ($(this).width()-40)+'px');
		button.bind('click', function() {
			scrollMultiPartContent('partGeneratePassword');
		});
	});
	$("input[type='password'].switchVisibility").each(function() {
		var button = $(document.createElement('div'));
		button.addClass('fieldButton');
		button.css('background-image', "url('images/abc.png')");
		$(this).css('width', ($(this).width()-40)+'px');
		$(this).after(button);
		button.bind('click', function() {
			// As IE < 9 doesn't allow for changing the type attribute, the "old" input gets cloned and replaced
			var ref = $(this).prev('input');
			var replaceObject = $(document.createElement('input'));
			replaceObject.attr('id', ref.attr('id'));
			replaceObject.attr('style', ref.attr('style'));
			replaceObject.attr('class', ref.attr('class'));
			replaceObject.attr('name', ref.attr('name'));
			replaceObject.attr('autocomplete', ref.attr('autocomplete'));
			replaceObject.attr('type', ref.attr('type') == 'password' ? 'text' : 'password');
			replaceObject.val(ref.val());
			ref.replaceWith(replaceObject);
		});
	});
}

function onNumberFieldInit() {
	$("input[type='text'].number").each(function() {
		var replaceObject = $(document.createElement('input'));
		replaceObject.attr('type', 'number');
		replaceObject.attr('min', '1');
		replaceObject.attr('max', '128');
		replaceObject.attr('id', $(this).attr('id'));
		replaceObject.attr('style', $(this).attr('style'));
		replaceObject.attr('class', $(this).attr('class'));
		replaceObject.attr('onchange', $(this).attr('onchange'));
		replaceObject.attr('oninput', $(this).attr('onchange'));
		replaceObject.attr('name', $(this).attr('name'));
		replaceObject.attr('autocomplete', $(this).attr('autocomplete'));
		replaceObject.val($(this).val());
		$(this).replaceWith(replaceObject);
	});
}

function bindPlaceholder(field, placeholder) {
	placeholder.bind('click', function() {
		window.setTimeout(function() {
			field.focus();
		}, 50);
	});
	placeholder.bind('mouseenter', function() {
		field.addClass('inputHover');
	});
	placeholder.bind('mouseleave', function() {
		field.removeClass('inputHover');
	});
	field.bind('change keyup keydown keypress', function() {
		if (field.val() == '') {
			placeholder.css('display', 'block');
		} else {
			placeholder.css('display', 'none');
		}
	});
}

function setFormFieldInformation(field, placeholderText, optional) {
	$(document).bind('contentDisplayed', function() {
		if (placeholderText && field.is(":visible")) {
			var placeholder = $(document.createElement('div'));
			placeholder.html((optional ? '<strong>optional:</strong> ' : '') + placeholderText);
			placeholder.addClass('placeholder');
			if (optional) placeholder.addClass('optional');
			placeholder.css({
				'left': field.position().left + 'px',
				'top': field.position().top + 'px'
			});
			field.parent().append(placeholder);
			bindPlaceholder(field, placeholder);
			field.trigger('change');
		}
	});
}

function applyFieldInformation() {
	if (typeof fieldInformation == 'undefined') return;
	for (var fieldId in fieldInformation) {
		var field = $('[id$=":'+fieldId+'"]');
		var info = fieldInformation[fieldId];
		if (field.length > 0) {
			setFormFieldInformation(field, info['placeholder'], info['optional']);
		}
	}
}

function onFormErrorsInit() {
	var mobile = isMobile();
	var errors = new Array();
	$('form .error').each(function() {
		if ($(this).text() && !$(this).parent('div').find("input[type='text'],input[type='password'],input[type='checkbox']").hasClass('valid')) {
			if (!mobile) {
				$(this).css('display', 'block');
				$(this).parent('div').find("input[type='text'],input[type='password'],.checkbox,label").addClass('erroneous');
			} else {
				errors.push({'field': $.trim($(this).parent('div').find('label').text()), 'error': $.trim($(this).text())});
				$(this).css('display', 'none');
			}
		} else {
			$(this).css('display', 'none');
			$(this).parent('div').find("input[type='text'],input[type='password'],.checkbox,label").removeClass('erroneous');
		}
	});
	if (mobile && errors.length > 0) {
		var s = '';
		for (var i=0; i<errors.length; i++) {
			var e = errors[i];
			s += e['field'] + ': ' + e['error'] + "\n";
		}
		$(window).load(function() {
			alert(s);
		});
	}
}

function initRangy() {
	rangy.init();
}

function displayContent() {
	$('#loading').hide();
	$('#contentContainer').show();
	$(document).trigger('contentDisplayed');
}

window.setInterval(function() {
	$.ajax({
		'contentType': 'text/plain',
		'type': 'GET',
		'url': './services/ping'
	});
}, 1000*5*60);

// Session timeout
$(document).ready(activateSessionTimeoutTimer);
$('html').bind('click', function() {
	activateSessionTimeoutTimer();
});

$(document).ready(checkPasswordSwitchCompatibility);
$(document).ready(checkBrowserCompatibility);
$(document).ready(onAddEntryFormInit);
$(document).ready(onImportFormInit);
$(document).ready(onExportFormInit);
$(document).ready(onEntryListInit);
$(document).ready(onMultiPartContentInit);
$(document).ready(setupPopupMenuClick);
$(document).ready(onChangePassphraseFormInit);
$(document).ready(onSignupFormInit);
$(document).ready(onResetPasswordFormInit);
$(document).ready(onCheckboxInit);
$(document).ready(onPasswordFieldInit);
$(document).ready(onNumberFieldInit);
$(document).ready(onSearchFormInit);
$(document).ready(onSelectInit);
$(document).ready(onDropdownMenuInit);
$(document).ready(applyFieldInformation);
$(document).ready(onFormErrorsInit);
$(document).ready(initRangy);
$(document).ready(displayContent);
$(document).bind('ready', focusForm);